package com.renu.jdependencyanalyser.freemarker.data;

import com.renu.jdependencyanalyser.cons.ProjectCons;
import com.renu.jdependencyanalyser.core.ClassBorderGene;
import com.renu.jdependencyanalyser.core.ProjectInfo;
import com.renu.jdependencyanalyser.model.ClassModel;
import com.renu.jdependencyanalyser.model.relation.DependRelation;
import com.renu.jdependencyanalyser.model.relation.ExtendRelation;
import com.renu.jdependencyanalyser.model.relation.ImplementRelation;
import com.renu.jdependencyanalyser.model.relation.Relation;
import com.renu.jdependencyanalyser.utils.MyProjectUtil;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class ClsData {
    private  ClassBorderGene classBorderGene;

    private ProjectInfo projectInfo;
    private  String clsName;

    private Set<String> outerFlds;

    private Set<String> indirOuterMthds;

    private Set<String> dirOuterMthds;


    private List<Relation> dependRelations;

    private List<Relation> extendRelations;

    private List<Relation> implementRelations;



    public ClsData(ProjectInfo projectInfo, ClassBorderGene classBorderGene) {
        this.classBorderGene = classBorderGene;
        this.projectInfo = projectInfo;
        init();
    }


    // todo todebug
    private void init () {
        String className = MyProjectUtil.convertClsSig2ClsName(classBorderGene.getClassModel().getClsSig());
        this.setClsName(className);
        this.setOuterFlds(classBorderGene.getDirOuterFields().stream().map(MyProjectUtil::convertFldsSig2FldName).collect(Collectors.toSet()));

        //List<String> list1 = classBorderGene.getDirOuterMethodSig().stream().map(methosSig -> MyProjectUtil.converMthdSig2MthdName(methosSig)).toList();
        Set<String> set1 = classBorderGene.getDirOuterMethodSig().stream().map(MyProjectUtil::converMthdSig2MthdName).collect(Collectors.toSet());
        this.setDirOuterMthds(set1);

        Set<String> set2 = classBorderGene.getIndirOuterMethodSig().stream().map(methosSig -> MyProjectUtil.converMthdSig2MthdName(methosSig)).collect(Collectors.toSet());
        //List<String> list2 = classBorderGene.getIndirOuterMethodSig().stream().map(methosSig -> MyProjectUtil.converMthdSig2MthdName(methosSig)).toList();
        this.setIndirOuterMthds(set2);

        dependRelations = new ArrayList<>();
        Set<String> dirDependClass = classBorderGene.getDirDependClass();
        for (String dependClass : dirDependClass) {
            String src = className;
            String tgt= MyProjectUtil.convertClsSig2ClsName(dependClass);
            dependRelations.add(new DependRelation(src,tgt));

        }


         extendRelations = new ArrayList<>();
         implementRelations = new ArrayList<>();
        String dirOrIndirOuterExtendClsSig = classBorderGene.getDirOrIndirOuterExtendClsSig();
        if (!StringUtils.isEmpty(dirOrIndirOuterExtendClsSig)){
            ClassModel extendCLs = projectInfo.getClassModel(dirOrIndirOuterExtendClsSig);
            if (extendCLs != null){ // 不是直接的
                findExtendAndImplemtRelations(extendCLs,extendRelations,implementRelations,projectInfo,1);
            }
            String tgt = MyProjectUtil.convertClsSig2ClsName(dirOrIndirOuterExtendClsSig);
            extendRelations.add(new ExtendRelation(className,tgt));
        }

        Set<String> dirOrIndirOuterImplementClsSigs = classBorderGene.getDirOrIndirOuterImplementClsSigs();
        for (String dirOrIndirOuterImplementClsSig : dirOrIndirOuterImplementClsSigs) {
            ClassModel implementCls = projectInfo.getClassModel(dirOrIndirOuterImplementClsSig);
            if (implementCls!= null){
                findExtendAndImplemtRelations(implementCls,extendRelations,implementRelations,projectInfo,1);
            }
            String tgt = MyProjectUtil.convertClsSig2ClsName(dirOrIndirOuterImplementClsSig);
            implementRelations.add(new ImplementRelation(className,tgt));

        }
    }

    private boolean findExtendAndImplemtRelations(ClassModel classModel,
                                                  List<Relation> extendRelations,
                                                  List<Relation> implementRelations,
                                                  ProjectInfo projectInfo, int dpth) {
        if (dpth == ProjectCons.MAX_DPTH_CLS){
            return false;
        }
        String clsSig  = classModel.getClsSig();
        String clsName = MyProjectUtil.convertClsSig2ClsName(clsSig);
        if (projectInfo.getOuterClassMap().containsKey(clsSig)){
            return true;
        }
        String extendClsSig = classModel.getExtendClsSig();
        if (!StringUtils.isEmpty(extendClsSig)){
            // todo todebug
            String extendClsName = MyProjectUtil.convertClsSig2ClsName(extendClsSig);
            if ( projectInfo.getOuterClassMap().containsKey(extendClsSig)){//说明是outerCls
                extendRelations.add(new ExtendRelation(clsName,extendClsName));
                return  true;
            }else{
                ClassModel extendCls = projectInfo.getClassModel(extendClsSig);
                if (findExtendAndImplemtRelations(extendCls,extendRelations,implementRelations,projectInfo,dpth+1)){
                    extendRelations.add(new ExtendRelation(clsName,extendClsName));
                }
            }
        }
        Set<String> implementClssSigs = classModel.getImplementClssSig();
        for (String implementClssSig : implementClssSigs) {
            String implementClsName = MyProjectUtil.convertClsSig2ClsName(implementClssSig);
            if (projectInfo.getOuterClassMap().containsKey(implementClssSig)){
                implementRelations.add(new ImplementRelation(clsName,implementClsName));
            }else{
                ClassModel implemtCls = projectInfo.getClassModel(implementClssSig);
                if (findExtendAndImplemtRelations(implemtCls, extendRelations, implementRelations, projectInfo, dpth + 1)) {
                    implementRelations.add(new ImplementRelation(clsName,implementClsName));
                }

            }

        }
        return false;


    }

    public String getClsName() {
        return clsName;
    }

    public void setClsName(String clsName) {
        this.clsName = clsName;
    }

    public Set<String> getOuterFlds() {
        return outerFlds;
    }

    public void setOuterFlds(Set<String> outerFlds) {
        this.outerFlds = outerFlds;
    }

    public Set<String> getIndirOuterMthds() {
        return indirOuterMthds;
    }

    public void setIndirOuterMthds(Set<String> indirOuterMthds) {
        this.indirOuterMthds = indirOuterMthds;
    }

    public Set<String> getDirOuterMthds() {
        return dirOuterMthds;
    }

    public void setDirOuterMthds(Set<String> dirOuterMthds) {
        this.dirOuterMthds = dirOuterMthds;
    }

    public List<Relation> getDependRelations() {
        return dependRelations;
    }

    public List<Relation> getExtendRelations() {
        return extendRelations;
    }

    public List<Relation> getImplementRelations() {
        return implementRelations;
    }
}
